from datetime import timedelta, datetime
from typing import Optional

from fastapi import Header, HTTPException
from passlib.context import CryptContext
from jose import JWTError, jwt
from pydantic import ValidationError
from config import CONFIG
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm, SecurityScopes
from fastapi import Depends, FastAPI, HTTPException, status
from models import Account
from exception import credentials_exception

# 使用的算法是Bcrypt
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/account/account/token")


async def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, CONFIG.SECRET_KEY, algorithms=CONFIG.ALGORITHM)
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception

    except JWTError as e:
        raise credentials_exception

    user: Account = await Account.get(mobile=username)
    if user is None:
        raise credentials_exception
    return user


async def get_current_active_user(current_user: Account = Depends(get_current_user)):
    if current_user.activate:
        raise HTTPException(status_code=400, detail="Inactive user")
    return current_user


def get_password_hash(password):
    """
    哈希来自用户的密码
    :param password: 原密码
    :return: 哈希后的密码
    """
    return pwd_context.hash(password)


def verify_password(plain_password, hashed_password):
    """
    校验接收的密码是否与存储的哈希值匹配
    :param plain_password: 原密码
    :param hashed_password: 哈希后的密码
    :return: 返回值为bool类型，校验成功返回True,反之False
    """
    return pwd_context.verify(plain_password, hashed_password)


def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    """

    :param data: 需要进行JWT令牌加密的数据（解密的时候会用到）
    :param expires_delta: 令牌有效期
    :return: token
    """
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=CONFIG.ACCESS_TOKEN_EXPIRE_MINUTES)
    # 添加失效时间
    to_encode.update({"exp": expire})
    # SECRET_KEY：密钥
    # ALGORITHM：JWT令牌签名算法
    encoded_jwt = jwt.encode(to_encode, CONFIG.SECRET_KEY, algorithm=CONFIG.ALGORITHM)
    return encoded_jwt


def check_jwt_token(token):
    """
    验证token
    :param token:
    :return: 返回用户信息
    """
    try:
        payload = jwt.decode(token, CONFIG.SECRET_KEY, algorithms=CONFIG.ALGORITHM)
        # 通过解析得到的username,获取用户信息,并返回
        return payload
    except (JWTError, jwt.ExpiredSignatureError, ValidationError):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail={
                'code': 5000,
                'message': "Token Error",
                'data': "Token Error",
            }
        )


if __name__ == '__main__':
    print(get_password_hash("woshishei"))
    passd = "$2b$12$9g7kBdTdaxEQol.F5kO5ROH9EVBChmDjSJV96MbUC/R8xNZOEtzaO"
    print(len(passd))
    print(verify_password("woshishei", passd))
